package com.nidu.demo.redis.service.impl;

import com.nidu.demo.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis服务实现类
 *
 * @author nidu
 */
@Slf4j
@Service
public class RedisServiceImpl implements RedisService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
        log.debug("[Redis] SET: key={}, value={}", key, value);
    }

    @Override
    public void set(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
        log.debug("[Redis] SET with expire: key={}, value={}, timeout={}, unit={}", 
                key, value, timeout, unit);
    }

    @Override
    public Object get(String key) {
        Object value = redisTemplate.opsForValue().get(key);
        log.debug("[Redis] GET: key={}, value={}", key, value);
        return value;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T get(String key, Class<T> type) {
        Object value = get(key);
        if (value == null) {
            return null;
        }
        try {
            return (T) value;
        } catch (ClassCastException e) {
            log.warn("[Redis] Type cast failed: key={}, expectedType={}, actualType={}", 
                    key, type.getName(), value.getClass().getName());
            return null;
        }
    }

    @Override
    public Boolean delete(String key) {
        Boolean result = redisTemplate.delete(key);
        log.debug("[Redis] DELETE: key={}, result={}", key, result);
        return result;
    }

    @Override
    public Long delete(String... keys) {
        Long result = redisTemplate.delete(Arrays.asList(keys));
        log.debug("[Redis] DELETE batch: keys={}, result={}", keys, result);
        return result;
    }

    @Override
    public Boolean hasKey(String key) {
        Boolean result = redisTemplate.hasKey(key);
        log.debug("[Redis] HAS_KEY: key={}, result={}", key, result);
        return result;
    }

    @Override
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        Boolean result = redisTemplate.expire(key, timeout, unit);
        log.debug("[Redis] EXPIRE: key={}, timeout={}, unit={}, result={}", 
                key, timeout, unit, result);
        return result;
    }

    @Override
    public Long getExpire(String key, TimeUnit unit) {
        Long result = redisTemplate.getExpire(key, unit);
        log.debug("[Redis] GET_EXPIRE: key={}, unit={}, result={}", key, unit, result);
        return result;
    }

    @Override
    public void hSet(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, value);
        log.debug("[Redis] HSET: key={}, field={}, value={}", key, field, value);
    }

    @Override
    public Object hGet(String key, String field) {
        Object value = redisTemplate.opsForHash().get(key, field);
        log.debug("[Redis] HGET: key={}, field={}, value={}", key, field, value);
        return value;
    }

    @Override
    public Map<Object, Object> hGetAll(String key) {
        Map<Object, Object> result = redisTemplate.opsForHash().entries(key);
        log.debug("[Redis] HGETALL: key={}, size={}", key, result.size());
        return result;
    }

    @Override
    public Long hDelete(String key, Object... fields) {
        Long result = redisTemplate.opsForHash().delete(key, fields);
        log.debug("[Redis] HDEL: key={}, fields={}, result={}", key, fields, result);
        return result;
    }

    @Override
    public Boolean hHasKey(String key, String field) {
        Boolean result = redisTemplate.opsForHash().hasKey(key, field);
        log.debug("[Redis] HHAS_KEY: key={}, field={}, result={}", key, field, result);
        return result;
    }

    @Override
    public Long lLeftPush(String key, Object value) {
        Long result = redisTemplate.opsForList().leftPush(key, value);
        log.debug("[Redis] LPUSH: key={}, value={}, result={}", key, value, result);
        return result;
    }

    @Override
    public Long lRightPush(String key, Object value) {
        Long result = redisTemplate.opsForList().rightPush(key, value);
        log.debug("[Redis] RPUSH: key={}, value={}, result={}", key, value, result);
        return result;
    }

    @Override
    public Object lLeftPop(String key) {
        Object value = redisTemplate.opsForList().leftPop(key);
        log.debug("[Redis] LPOP: key={}, value={}", key, value);
        return value;
    }

    @Override
    public Object lRightPop(String key) {
        Object value = redisTemplate.opsForList().rightPop(key);
        log.debug("[Redis] RPOP: key={}, value={}", key, value);
        return value;
    }

    @Override
    public List<Object> lRange(String key, long start, long end) {
        List<Object> result = redisTemplate.opsForList().range(key, start, end);
        log.debug("[Redis] LRANGE: key={}, start={}, end={}, size={}", 
                key, start, end, result != null ? result.size() : 0);
        return result;
    }

    @Override
    public Long lSize(String key) {
        Long result = redisTemplate.opsForList().size(key);
        log.debug("[Redis] LLEN: key={}, result={}", key, result);
        return result;
    }

    @Override
    public Long sAdd(String key, Object... values) {
        Long result = redisTemplate.opsForSet().add(key, values);
        log.debug("[Redis] SADD: key={}, values={}, result={}", key, values, result);
        return result;
    }

    @Override
    public Long sRemove(String key, Object... values) {
        Long result = redisTemplate.opsForSet().remove(key, values);
        log.debug("[Redis] SREM: key={}, values={}, result={}", key, values, result);
        return result;
    }

    @Override
    public Boolean sIsMember(String key, Object value) {
        Boolean result = redisTemplate.opsForSet().isMember(key, value);
        log.debug("[Redis] SISMEMBER: key={}, value={}, result={}", key, value, result);
        return result;
    }

    @Override
    public Set<Object> sMembers(String key) {
        Set<Object> result = redisTemplate.opsForSet().members(key);
        log.debug("[Redis] SMEMBERS: key={}, size={}", key, result != null ? result.size() : 0);
        return result;
    }

    @Override
    public Long sSize(String key) {
        Long result = redisTemplate.opsForSet().size(key);
        log.debug("[Redis] SCARD: key={}, result={}", key, result);
        return result;
    }

    @Override
    public Boolean zAdd(String key, Object value, double score) {
        Boolean result = redisTemplate.opsForZSet().add(key, value, score);
        log.debug("[Redis] ZADD: key={}, value={}, score={}, result={}", key, value, score, result);
        return result;
    }

    @Override
    public Long zRemove(String key, Object... values) {
        Long result = redisTemplate.opsForZSet().remove(key, values);
        log.debug("[Redis] ZREM: key={}, values={}, result={}", key, values, result);
        return result;
    }

    @Override
    public Set<Object> zRange(String key, long start, long end) {
        Set<Object> result = redisTemplate.opsForZSet().range(key, start, end);
        log.debug("[Redis] ZRANGE: key={}, start={}, end={}, size={}", 
                key, start, end, result != null ? result.size() : 0);
        return result;
    }

    @Override
    public Long zSize(String key) {
        Long result = redisTemplate.opsForZSet().zCard(key);
        log.debug("[Redis] ZCARD: key={}, result={}", key, result);
        return result;
    }

    @Override
    public Double zScore(String key, Object value) {
        Double result = redisTemplate.opsForZSet().score(key, value);
        log.debug("[Redis] ZSCORE: key={}, value={}, result={}", key, value, result);
        return result;
    }
}
